﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;

using EncryptionClassLibrary.Encryption;

namespace MakeIT.Deo.Negocios
{
    /// <summary>
    /// Classe que reune os métodos relativos ao Cliente - Herda da classe base NegocioBase
    /// </summary>
    public class ClienteBO
    {

        private deoEntities modelo = null;

        public ClienteBO()
        {
            modelo = new deoEntities();
        }

        /// <summary>
        /// Salva um novo registro ou atualiza um já existente
        /// </summary>
        /// <param name="entidade">Objeto a ser gravado/atualizadao em banco de dados</param>
        /// <param name="novo">Determina se um novo registro ou não</param>
        public void SalvarCliente(cliente entidade, Boolean novo)
        {
            try
            {

                if (entidade.Pass != null && entidade.Pass.Length > 0)
                {
                    entidade.Pass = EncryptPassword(entidade.Pass);
                }

                
                // Verifica se eh um registro novo
                if (novo)
                {
                    // Insere o regisro na tabela de Cliente
                    modelo.AddTocliente(entidade);
                }
                else
                {
                    //Efetiva as mudanças na entidade já existente
                    modelo.ApplyPropertyChanges(entidade.EntityKey.EntitySetName, entidade);
                }

                // Efetiva a trasação no Banco
                modelo.SaveChanges();
                
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// Recupera uma lista de Cliente 
        /// </summary>
        /// <param name="idCliente">Codigo do Cliente</param>
        /// <param name="nomeCliente">Nome do cliente usado no filtro da query (like)</param>
        /// <returns>Lista de Cliente</returns>
        public List<cliente> RecuperaCliente(int? idCliente, string nomeCliente, string userName, string email, bool? ativo, string tipo)
        {

            try
            {
                // Declara objetos
                IQueryable<cliente> query = modelo.cliente;

                // Verifica se o código do cliente é diferente de nulo
                if (idCliente != null)
                {
                    // monta query dinamica
                    query = query.Where(a => a.IdCliente == idCliente);
                }

                // Verifica se filtro nomeCliente é diferente de vazio ou nulo
                if (!string.IsNullOrEmpty(nomeCliente))
                {
                    // monta query dinamica
                    query = query.Where(a => a.Nome.Contains(nomeCliente));
                }

                // Verifica se filtro userName é diferente de vazio ou nulo
                if (!string.IsNullOrEmpty(userName))
                {
                    // monta query dinamica
                    query = query.Where(a => a.User.Equals(userName));
                }
                // Verifica se filtro userName é diferente de vazio ou nulo
                if (!string.IsNullOrEmpty(email))
                {
                    // monta query dinamica
                    query = query.Where(a => a.Email.Equals(email));
                }

                // Verifica filtro ativo
                if (ativo!=null && (bool)ativo)
                {
                    // monta query dinamica
                    query = query.Where(a => (bool)a.Ativo);
                }

                if (tipo != null)
                    query = query.Where(a => a.Tipo.Equals(tipo));

                // Executa Query
                var retornaLista = from user in query
                                   orderby user.Tipo, user.IdCliente
                                   select user;

                if (retornaLista!=null && retornaLista.Count() > 0)
                {
                    foreach (cliente user in retornaLista)
                        if (user.Pass.Length>0)
                            user.Pass = DecryptPassword(user.Pass);
                    
                    return retornaLista.ToList();

                }
                else
                {
                    return null;
                }

            }
            catch (Exception e)
            {
                throw e; //TODO: Tratar a exceção
            }
        }

        /// <summary>
        /// Recupera o Cliente pelo código.
        /// </summary>
        /// <param name="idCliente">Código do Cliente</param>
        /// <returns>Lista de cliente</returns>
        public cliente RecuperaCliente(int? idCliente)
        {
            List<cliente> listaCliente = RecuperaCliente(idCliente, null, null, null, false, null);
            if (listaCliente!=null && listaCliente.Count>0)
                return listaCliente[0];
            else
                return null;
        }

        /// <summary>
        /// Recupera o Cliente pelo nome (like)
        /// </summary>
        /// <param name="nomeCliente">Nome do Cliente</param>
        /// <returns>Lista de clientes</returns>
        public List<cliente> RecuperaCliente(string nomeCliente)
        {
            return RecuperaCliente(null, nomeCliente, null, null, false, null);
        }

        /// <summary>
        /// Recupera os Clientes ativos
        /// </summary>
        /// <param name="ativo">ativo</param>
        /// <returns>Lista de clientes</returns>
        public List<cliente> RecuperaCliente(bool ativo)
        {
            return RecuperaCliente(null, null, null, null, ativo, null);
        }

        /// <summary>
        /// Recupera todos os registros Cliente
        /// </summary>        
        /// <returns>Lista de Clientes</returns>
        public List<cliente> RecuperaCliente()
        {
            // chama o método de mesmo nome (overload) passando apenas o parametro pertinente
            return this.RecuperaCliente(null, null, null, null, false, null);
        }

        /// <summary>
        /// Excluir um determinado registro 
        /// </summary>
        /// <param name="entidade">Registro a ser excluido</param>
        /// <param name="msg"></param>
        /// <returns>Retorna uma msg quando há, a qual sinaliza algum fluxo alternativo</returns>
        public void DeletaCliente(cliente cliente)
        {
            try
            {
                EntityKey key = new EntityKey(modelo.DefaultContainerName + ".cliente", "IdCliente", cliente.IdCliente);
                modelo.DeleteObject(modelo.GetObjectByKey(key));
                modelo.SaveChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static string EncryptPassword(string password)
        {
            try
            {
                Symmetric sym = new Symmetric(Symmetric.Provider.Rijndael, true);
                Data key = new Data("Banana nanica");
                Data encryptedData = new Data();

                encryptedData = sym.Encrypt(new Data(password), key);
                string base64EncryptedString = encryptedData.ToBase64();
                return base64EncryptedString;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        
        public static string DecryptPassword(string password){

            try
            {
                Symmetric sym = new Symmetric(Symmetric.Provider.Rijndael, true);
                Data key = new Data("Banana nanica");
                Data encryptedData = new Data();
                encryptedData.Base64 = password;
                Data decryptedData = new Data();
                decryptedData = sym.Decrypt(encryptedData, key);
                return decryptedData.ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

    }

}
